package org.hoyi.staticcache;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.hoyi.DB.comment.DbAttrANNO;
import org.hoyi.DB.conf.HOYIConf;
import org.hoyi.DB.ctrl.Console;
import org.hoyi.DB.ents.Entity;
import org.hoyi.dispatchs.DispatchConfig;
import org.hoyi.disptachs.model.JsonLibCtrls;
import org.hoyi.microservice.HoyiCloudApplication;
import org.hoyi.microservice.api.anno.ApiEntityPara;
import org.hoyi.microservice.api.anno.ApiPara;
import org.hoyi.microservice.api.anno.Apidoc;
import org.hoyi.microservice.api.model.APICons;
import org.hoyi.microservice.api.model.APIEnti;
import org.hoyi.microservice.api.model.APIPara;
import org.hoyi.wb.comment.RequestMethod;
import org.hoyi.wb.comment.RequestMode;
import org.hoyi.wb.comment.UnApiDoc;

import net.sf.json.JSONObject;

/**
 * 
 * Hoyi-web 静态化处理。
 * 
 * 将hoyi page ,缓存到内存中，读取的时候，直接从内存中读取，可以加快执行效率.
 * 
 * @author ellen
 * 
 *
 */
public class HoyiPageStaticCache {

	private static HoyiPageStaticCache _instance;

	public static HoyiPageStaticCache getInstance() {
		if (_instance == null) {
			_instance = new HoyiPageStaticCache();
		}
		return _instance;
	}
	
	/**
	 * 当前系统所有的模块.一个微服务也可以注册为一个模块.
	 */
	public Map<String, String> Modules = new HashMap<>();

	/**
	 * 缓存的所有hoyi page.
	 */
	public Map<String, Class<?>> hoyipagescache = new HashMap<>();

	/**
	 * reqmapping, 请求的路径.
	 */
	public Map<String, ReqMapInfo> reqmapping = new HashMap<>();

	/**
	 * hoyi page 当前页面定义的方法.
	 */
//	public Map<String, Map<String, Method>> hoyideclaredMethods = new HashMap<>();

	/**
	 * hoyi page 的方法缓存.
	 */
//	public Map<String, Map<String, Method>> hoyipagemethods = new HashMap<>();

	/**
	 * hoyi page 的字段缓存.
	 */
//	public Map<String,Map<String, Field>> hoyipagefields = new HashMap<>();
//	
//	/**
//	 * hoyi page 当前页面定义的字段.
//	 */
//	public Map<String, Map<String, Field>> hoyideclaredFields = new HashMap<>();

	/**
	 * 是否已经静态缓存 。
	 */
	public boolean StaticCahced = false;

	/**
	 * 开始缓存，系统启动时候开始缓存.
	 */
	public void BeginStaticCache() {
		String packageName = "WebRoot";
		DispatchConfig.ConsoleMapping = Boolean.parseBoolean(HoyiCloudApplication.hoyiconfig.getHOYI().getOrDefault("ConsoleMapping", "false"));
//        List<Class<?>> Classes = PackageClassUtil.getClassName(packageName);
		try {

			Set<Class<?>> Classes = PackageClassUtil2.getClasses(packageName);
			String tmpclass = "";
			if (Classes != null) {
				// API DOC相关
				String classModule = "";
				String classCates = "";
				
				for (Class<?> curclass : Classes) {

//					Console.Info("");

					if (curclass.getName().startsWith("WebRoot.")) {
						tmpclass = curclass.getName().substring(8, curclass.getName().length());
						tmpclass = tmpclass.replace(".", "/");
//		                	tmpclass = tmpclass + HOYIConf.Suffix;
					}
					hoyipagescache.put(tmpclass, curclass);
					if(DispatchConfig.ConsoleMapping) {
						Console.Info("tmpclass:" + tmpclass);	
					}

					ReqMapInfo _pgmapinfos = new ReqMapInfo();
					_pgmapinfos.reqclass = curclass;
					_pgmapinfos.pgreq = true; // 标明示页面请求.
					_pgmapinfos.requrl = "/" + tmpclass + HOYIConf.Suffix;
					_pgmapinfos.reqmethods = null;

					reqmapping.put(_pgmapinfos.requrl, _pgmapinfos);
					// API Doc 相关.
					Apidoc doc;
					if(curclass.isAnnotationPresent(Apidoc.class)) {
						doc = curclass.getAnnotation(Apidoc.class);
						if(doc.Module() != null && doc.Module().length() > 0) {
							classModule = doc.Module();
						}
						if(doc.Cates() != null && doc.Cates().length() > 0) {
							classCates = doc.Cates();
						}
					}

					Map<String, Method> tmpdeclaredmethods = new HashMap<>();
					for (Method mth : curclass.getDeclaredMethods()) {
						// 只缓存void的方法.其他方法不缓存.意思是根目录的读取不到？
						boolean cancached = false;
						if (mth.getReturnType().toString().toLowerCase().equals("void")) { 
							cancached = true;
						}
						if(mth.getName() == "OnPreInit") {
							cancached = false;
						}
//						else {
//							Console.Info(curclass.toString() + ":" + mth.getName());
//						}
						
						String mthreqtype = "";
						String methodrequrl = "";
						if(cancached) {
							tmpdeclaredmethods.put(mth.getName(), mth);

							ReqMapInfo _mapinfos = new ReqMapInfo();
							_mapinfos.reqclass = curclass;
							_mapinfos.requrl = "/" + tmpclass + "/" + mth.getName() + HOYIConf.Suffix;
							methodrequrl = tmpclass + "/" + mth.getName() + HOYIConf.Suffix;
							_mapinfos.reqmethods = mth;

							// Request Type 块.
							if (mth.isAnnotationPresent(RequestMethod.class)) {
								Annotation anos = mth.getAnnotation(RequestMode.class);

								_mapinfos.requestTypes = ((RequestMode) anos).MODE();
								mthreqtype =  ((RequestMode) anos).MODE().toString();
							}
							reqmapping.put(_mapinfos.requrl, _mapinfos);
						}
						// API Doc 相关.
						if(!curclass.isAnnotationPresent(UnApiDoc.class)) {
							if(mth.isAnnotationPresent(Apidoc.class)) {
								Apidoc methoddoc = mth.getAnnotation(Apidoc.class);
								if(methoddoc.Module() != null && methoddoc.Module().length() > 0) {
									classModule = methoddoc.Module();
								}
								if(methoddoc.Cates() != null && methoddoc.Cates().length() > 0) {
									classCates = methoddoc.Cates();
								}
								APIEnti enti = new APIEnti(classModule, classCates, methoddoc.Notes(), methodrequrl, mthreqtype);
								enti.retValue = mth.getReturnType().toString();
								enti.CanReq = cancached;
								
								APIPara tmppara;
								for (ApiPara _pp : methoddoc.paras()) {
									tmppara = new APIPara(_pp.Comment(), _pp.Name(), _pp.CHARType(), _pp.Notes(), _pp.Required());
									enti.AddPara(tmppara);
								}
								APIPara tmpresponse;
								for (ApiPara _px : methoddoc.response()) {
									tmpresponse = new APIPara(_px.Comment(), _px.Name(), _px.CHARType(), _px.Notes(), _px.Required());
									enti.AddResponse(tmpresponse);
								}
								
								Entity tempEntity;
								Field field;
								DbAttrANNO tempdbattr;
								for (ApiEntityPara entipa : methoddoc.entityparas()) {
									if(entipa.Entity() != null && entipa.Entity().toString().length() > 0) {
										tempEntity = (Entity) entipa.Entity().newInstance();
										JSONObject arr = JSONObject.fromObject(tempEntity, JsonLibCtrls.getjsonConfig());
										//Console.Info("ARR-------------->" + arr);
										Iterator skeyiter = arr.keys();
										while (skeyiter.hasNext()) {
											String skey = skeyiter.next().toString();
											
											field = entipa.Entity().getDeclaredField("_" + skey);
											if(field != null) {
												if(field.isAnnotationPresent(DbAttrANNO.class)) {
													tempdbattr = field.getAnnotation(DbAttrANNO.class);
													tmppara = new APIPara(tempdbattr.Comment() + "." + tempEntity.get_tableName() , tempdbattr.FieldName(), tempdbattr.type().toString(), tempdbattr.FieldName(), false);
													enti.AddPara(tmppara);
												}else {
													tmppara = new APIPara(tempEntity.get_tableName() + "." , skey, "String", skey, false);
													enti.AddPara(tmppara);
												}
											}else {
												tmppara = new APIPara(tempEntity.get_tableName() + "." , skey, "String", skey, false);
												enti.AddPara(tmppara);
											}
										}
									}
								}
						    	APICons.getInstance().AddAPI(classModule, classCates, enti);
							}
						}
					}

					for (String _keys : reqmapping.keySet()) {
						if(DispatchConfig.ConsoleMapping) {
							Console.Info("mapping:" + _keys);
						}
					}
//					Console.Info("");
				}
			}
		} catch (Exception e) {
			// TODO: handle exception
		}

		Console.Info("Cache Page Finished, MAPPING.SIZE:" + reqmapping.size());
		
//        String tmpclass = "";
//        if (Classes != null) {  
//            for (Class<?> curclass : Classes) {  
//
//                Console.Info("");
//            	
//            	if(curclass.getName().startsWith("WebRoot.")) {
//                	tmpclass = curclass.getName().substring(8, curclass.getName().length());
//                	tmpclass = tmpclass.replace(".", "/");
////                	tmpclass = tmpclass + HOYIConf.Suffix;
//            	}
//            	hoyipagescache.put(tmpclass, curclass);
//                
//                Console.Info("tmpclass:" + tmpclass);  
//                
//        		ReqMapInfo _pgmapinfos = new ReqMapInfo();
//        		_pgmapinfos.reqclass = curclass;
//        		_pgmapinfos.pgreq = true; // 标明示页面请求.
//        		_pgmapinfos.requrl = "/" + tmpclass +  HOYIConf.Suffix;
//        		_pgmapinfos.reqmethods = null;
//				
//				reqmapping.put(_pgmapinfos.requrl, _pgmapinfos);
//                
//// --------------------------------    暂时不用.  ---------------------------------------------------------------- 
//                
//                
////              Console.Info("CACHE PAGE:" + curclass);  
//            	
////            	Map<String, Method> tmpmethods = new HashMap<>();
////            	for (Method mth : curclass.getMethods()) {
////            		tmpmethods.put(mth.getName(), mth);
//////					Console.Info("tmpmethods:" + mth.getName() + "," + mth);
////				}
////            	Console.Info("tmpmethods.size:" + tmpmethods.size());
////            	hoyipagemethods.put(tmpclass, tmpmethods);
//                
////            	Map<String, Field> tmpfields = new HashMap<>();
////            	for (Field fld : curclass.getFields()) {
////            		tmpfields.put(fld.getName(), fld);
//////					Console.Info("tmpfields:" + fld.getName() + "," + fld);
////				}
////            	Console.Info("tmpfields.size:" + tmpfields.size());
////            	hoyipagefields.put(tmpclass, tmpfields);
//            	
//            	
////            	Map<String, Field> tmpdeclaredField = new HashMap<>();
////            	for (Field fld : curclass.getDeclaredFields()) {
////            		tmpdeclaredField.put(fld.getName(), fld);
//////					Console.Info("tmpdeclaredField:" + fld.getName() + "," + fld);
////				}
////            	Console.Info("tmpfields.size:" + tmpdeclaredField.size());
////            	hoyideclaredFields.put(tmpclass, tmpdeclaredField);
//            	
//                
//// --------------------------------    暂时不用.  ---------------------------------------------------------------- 
//            	
//            	
//            	Map<String, Method> tmpdeclaredmethods = new HashMap<>();
//            	for (Method mth : curclass.getDeclaredMethods()) {
//            		tmpdeclaredmethods.put(mth.getName(), mth);
////					Console.Info("tmpdeclaredmethods:" + mth.getName() + "," + mth);
//					
//					ReqMapInfo _mapinfos = new ReqMapInfo();
//					_mapinfos.reqclass = curclass;
//					_mapinfos.requrl = "/" + tmpclass + "/" + mth.getName() + HOYIConf.Suffix;
//					_mapinfos.reqmethods = mth;
//					
//					// Request Type 块.
//					if(mth.isAnnotationPresent(RequestMethod.class)) {
//						Annotation anos = mth.getAnnotation(RequestMode.class);
//						
//						_mapinfos.requestTypes = ((RequestMode)anos).MODE();
//					}
//					reqmapping.put(_mapinfos.requrl, _mapinfos);
//				}
//            	
//            	for (String _keys : reqmapping.keySet()) {
//					Console.Info("mapping:" + _keys);
//				}
//            	
////            	Console.Info("tmpmethods.size:" + tmpdeclaredmethods.size());
////            	hoyideclaredMethods.put(tmpclass, tmpdeclaredmethods);
//            	
//            	
//
//                
//                Console.Info("");
//            }  
//        }  
	}

	/**
	 * 根据地址获取 Map Info.
	 * 
	 * @param _uri
	 * @return value
	 */
	public ReqMapInfo GetMapByURI(String _uri) {
		return reqmapping.get(_uri);
	}
	
	/**
	 * 获取所有的Mapping.
	 * @return value
	 */
	public Map<String, ReqMapInfo>  GetMaps() {
		return reqmapping;
	}
	/**
	 * 重启的时候需要把缓存的类重新清空一下.
	 */
	public void ClearMaps() {
		reqmapping.clear();
		reqmapping = new HashMap<String, ReqMapInfo>();
	}

}
